import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;

public final class Modifications {

	private final ArrayList<VSensorConfig> addVirtualSensors = new ArrayList<VSensorConfig>();
	private final ArrayList<VSensorConfig> removeVirtualSensors = new ArrayList<VSensorConfig>();

	public ArrayList<VSensorConfig> getAdd() {
		return addVirtualSensors;
	}

	public void setAdd(final Collection<String> add) {
		addVirtualSensors.clear();
		ArrayList<VSensorConfig> toAdd = new ArrayList<VSensorConfig>();
		loadVirtualSensors(add, toAdd);
		for (VSensorConfig vConfig : toAdd)
			addVirtualSensors.add(vConfig); // add configure object to list

	}

	private void loadVirtualSensors(Collection<String> fileNames,
			ArrayList<VSensorConfig> list) {
		if (fileNames == null || list == null)
			throw new RuntimeException("Null pointer Exception ("
					+ (fileNames == null) + "),(" + (list == null) + ")");
		String path = System.getProperty("user.dir") + "/xml.xsd";
		try {
			JAXBContext jc = JAXBContext.newInstance(VSensorConfig.class);
			Unmarshaller unmarshaller = jc.createUnmarshaller();
			VSensorConfig configuration;
			for (String filePath : fileNames) {
				File xml = new File(filePath);
//				if (!this.isConfigFileValid(filePath, path))
//					return;
				configuration = (VSensorConfig) unmarshaller.unmarshal(xml);
				configuration.setFileName(filePath);
				System.out.println("UUID = " + UUID.randomUUID().toString());
				list.add(configuration);
			}
		} catch (JAXBException e) {
			e.printStackTrace();
		}

	}

	boolean isConfigFileValid(String xmlFilePath, String xsdFilePath) {
		// judge the configure file whether valid or not
		try {

			InputStream isSchema = new FileInputStream(xsdFilePath);
			InputStream isXML = new FileInputStream(xmlFilePath);
			String strLang = XMLConstants.W3C_XML_SCHEMA_NS_URI;
			SchemaFactory factory = SchemaFactory.newInstance(strLang);
			StreamSource ss = new StreamSource(isSchema);
			Schema schema = factory.newSchema(ss);
			Validator validator = schema.newValidator();
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setNamespaceAware(true);
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document document = db.parse(isXML);
			DOMSource source = new DOMSource(document);
			validator.validate(source);
			System.out.println("Result : Valid!");
			return true;
		} catch (Exception e) {
			//e.printStackTrace();
			System.out.println(xmlFilePath + "Validation Result : Invalid!");
			return false;
		}
	}

	public ArrayList<VSensorConfig> getRemove() {
		return removeVirtualSensors;
	}

	public void setRemove(final Collection<String> listOfRemovedVirtualSensors) {
		removeVirtualSensors.clear();
		// file has been removed, the virtual sensor and dependent virtual
		// sensors should be deleted
		for (String fileName : listOfRemovedVirtualSensors) {
			VSensorConfig vSensorConfig = Mappings
					.getVSensorConfigByFileName(fileName);
			removeVirtualSensors.add(vSensorConfig);// add object to remove list
		}
	}

	/**
	 * Construct a new Modifications object.
	 * 
	 * @param add
	 *            : The list of the virtual sensor descriptor files added.
	 * @param remove
	 *            : The list of the virtual sensor descriptor files removed.
	 */
	public Modifications(final Collection<String> add,
			final Collection<String> remove) {
		// the order of the following two methods is important
		setRemove(remove);
		setAdd(add);
	}

}
